🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / feature / firmware / src / commonMain / kotlin / org / meshtastic / feature / firmware / FirmwareUpdateViewModel.kt
Displaying Raw • Download
feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/FirmwareUpdateViewModel.kt 9fa9f1e341ee8d2c8fd9fabf9253b2f012fc8c95 (9fa9f1e3) Text, 46.69 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.feature.firmware
Tff7b72import T7ee787androidx.lifecycle.ViewModel
Tff7b72import T7ee787androidx.lifecycle.viewModelScope
Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787kotlinx.coroutines.CancellationException
Tff7b72import T7ee787kotlinx.coroutines.CoroutineStart
Tff7b72import T7ee787kotlinx.coroutines.DelicateCoroutinesApi
Tff7b72import T7ee787kotlinx.coroutines.Job
Tff7b72import T7ee787kotlinx.coroutines.NonCancellable
Tff7b72import T7ee787kotlinx.coroutines.delay
Tff7b72import T7ee787kotlinx.coroutines.flow.Flow
Tff7b72import T7ee787kotlinx.coroutines.flow.MutableStateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.StateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.asStateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.collectLatest
Tff7b72import T7ee787kotlinx.coroutines.flow.filterNotNull
Tff7b72import T7ee787kotlinx.coroutines.flow.first
Tff7b72import T7ee787kotlinx.coroutines.flow.flowOf
Tff7b72import T7ee787kotlinx.coroutines.launch
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787kotlinx.coroutines.withTimeoutOrNull
Tff7b72import T7ee787org.jetbrains.compose.resources.StringResource
Tff7b72import T7ee787org.koin.core.annotation.KoinViewModel
Tff7b72import T7ee787org.meshtastic.core.common.di.ApplicationCoroutineScope
Tff7b72import T7ee787org.meshtastic.core.common.state.HiddenFeaturesUnlock
Tff7b72import T7ee787org.meshtastic.core.common.util.CommonUri
Tff7b72import T7ee787org.meshtastic.core.common.util.safeCatching
Tff7b72import T7ee787org.meshtastic.core.database.entity.FirmwareRelease
Tff7b72import T7ee787org.meshtastic.core.database.entity.FirmwareReleaseType
Tff7b72import T7ee787org.meshtastic.core.datastore.BootloaderWarningDataSource
Tff7b72import T7ee787org.meshtastic.core.datastore.FirmwareRecoveryDataSource
Tff7b72import T7ee787org.meshtastic.core.datastore.model.PendingFirmwareRecovery
Tff7b72import T7ee787org.meshtastic.core.model.ConnectionState
Tff7b72import T7ee787org.meshtastic.core.model.DeviceHardware
Tff7b72import T7ee787org.meshtastic.core.model.InterfaceId
Tff7b72import T7ee787org.meshtastic.core.model.MyNodeInfo
Tff7b72import T7ee787org.meshtastic.core.model.util.anonymize
Tff7b72import T7ee787org.meshtastic.core.repository.DeviceHardwareRepository
Tff7b72import T7ee787org.meshtastic.core.repository.FirmwareReleaseRepository
Tff7b72import T7ee787org.meshtastic.core.repository.NodeRepository
Tff7b72import T7ee787org.meshtastic.core.repository.PlatformAnalytics
Tff7b72import T7ee787org.meshtastic.core.repository.RadioController
Tff7b72import T7ee787org.meshtastic.core.repository.RadioPrefs
Tff7b72import T7ee787org.meshtastic.core.repository.isBle
Tff7b72import T7ee787org.meshtastic.core.repository.isSerial
Tff7b72import T7ee787org.meshtastic.core.repository.isTcp
Tff7b72import T7ee787org.meshtastic.core.resources.Res
Tff7b72import T7ee787org.meshtastic.core.resources.UiText
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_recovery_ble_failed
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_archive_missing_target
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_battery_low
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_context_changed
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_copying
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_extracting
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_failed
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_filename_unavailable
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_flashing
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_invalid_local_file_detail
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_method_ble
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_method_usb
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_method_wifi
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_missing_target
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_no_device
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_node_info_missing
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_requires_bin
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_requires_ota_zip
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_requires_uf2
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_unknown_error
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_unknown_hardware
Tff7b72import T7ee787org.meshtastic.core.resources.firmware_update_unsupported_update_method
Tff7b72import T7ee787org.meshtastic.core.resources.unknown
Tff7b72private Tff7b72const Tff7b72val Te6edf3DEVICE_DETACH_TIMEOUT Tff7b72= T79c0ff3T79c0ff0Te6edf3_000L
Tff7b72private Tff7b72const Tff7b72val Te6edf3VERIFY_TIMEOUT Tff7b72= T79c0ff6T79c0ff0Te6edf3_000L
Tff7b72private Tff7b72const Tff7b72val Te6edf3VERIFY_DELAY Tff7b72= T79c0ff2T79c0ff0T79c0ff0T79c0ff0L
Tff7b72private Tff7b72const Tff7b72val Te6edf3MIN_BATTERY_LEVEL Tff7b72= T79c0ff1T79c0ff0
Tff7b72private Tff7b72const Tff7b72val Te6edf3LOCAL_RELEASE_ID Tff7b72= Ta5d6ff"Ta5d6fflocalTa5d6ff"
Tff7b72private Tff7b72val Te6edf3BLUETOOTH_ADDRESS_REGEX Tff7b72= Te6edf3RegexTb4b4b4(Ta5d6ff"Ta5d6ff([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}Ta5d6ff"Tb4b4b4)
T8b949e/**
* ViewModel driving the firmware update screen. Coordinates release checking, file retrieval, transport-specific update
* execution, and post-update device verification.
*/
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffLongParameterListTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffTooManyFunctionsTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffLargeClassTa5d6ff"Tb4b4b4)
Tf0883e@KoinViewModel
Tff7b72class T56d364FirmwareUpdateViewModelTb4b4b4(
Tff7b72private Tff7b72val Te6edf3firmwareReleaseRepositoryTb4b4b4: Te6edf3FirmwareReleaseRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3deviceHardwareRepositoryTb4b4b4: Te6edf3DeviceHardwareRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3nodeRepositoryTb4b4b4: Te6edf3NodeRepositoryTb4b4b4,
Tff7b72private Tff7b72val Te6edf3radioControllerTb4b4b4: Te6edf3RadioControllerTb4b4b4,
Tff7b72private Tff7b72val Te6edf3radioPrefsTb4b4b4: Te6edf3RadioPrefsTb4b4b4,
Tff7b72private Tff7b72val Te6edf3bootloaderWarningDataSourceTb4b4b4: Te6edf3BootloaderWarningDataSourceTb4b4b4,
Tff7b72private Tff7b72val Te6edf3firmwareRecoveryDataSourceTb4b4b4: Te6edf3FirmwareRecoveryDataSourceTb4b4b4,
Tff7b72private Tff7b72val Te6edf3firmwareUpdateManagerTb4b4b4: Te6edf3FirmwareUpdateManagerTb4b4b4,
Tff7b72private Tff7b72val Te6edf3usbManagerTb4b4b4: Te6edf3FirmwareUsbManagerTb4b4b4,
Tff7b72private Tff7b72val Te6edf3fileHandlerTb4b4b4: Te6edf3FirmwareFileHandlerTb4b4b4,
Tff7b72private Tff7b72val Te6edf3applicationScopeTb4b4b4: Te6edf3ApplicationCoroutineScopeTb4b4b4,
Tff7b72private Tff7b72val Te6edf3hiddenFeaturesUnlockTb4b4b4: Te6edf3HiddenFeaturesUnlockTb4b4b4,
Tff7b72private Tff7b72val Te6edf3analyticsTb4b4b4: Te6edf3PlatformAnalyticsTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3ViewModelTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72private Tff7b72val Te6edf3_state Tff7b72= Te6edf3MutableStateFlowTff7b72<Te6edf3FirmwareUpdateStateTff7b72>Tb4b4b4(Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3IdleTb4b4b4)
Tff7b72val Te6edf3stateTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3FirmwareUpdateStateTff7b72> Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3connectionState Tff7b72= Te6edf3radioControllerTb4b4b4.Te6edf3connectionState
T8b949e/** The version-row easter egg also unlocks the nightly preview channel, like the web flasher's konami code. */
Tff7b72val Te6edf3nightlyUnlockedTb4b4b4: Te6edf3StateFlowTff7b72<Tffa657BooleanTff7b72> Tff7b72= Te6edf3hiddenFeaturesUnlockTb4b4b4.Te6edf3unlocked
Tff7b72private Tff7b72val Te6edf3_selectedReleaseType Tff7b72= Te6edf3MutableStateFlowTb4b4b4(Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3STABLETb4b4b4)
Tff7b72val Te6edf3selectedReleaseTypeTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3FirmwareReleaseTypeTff7b72> Tff7b72= Te6edf3_selectedReleaseTypeTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3_selectedRelease Tff7b72= Te6edf3MutableStateFlowTff7b72<Te6edf3FirmwareRelease?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4)
Tff7b72val Te6edf3selectedReleaseTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3FirmwareRelease?Tff7b72> Tff7b72= Te6edf3_selectedReleaseTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3_deviceHardware Tff7b72= Te6edf3MutableStateFlowTff7b72<Te6edf3DeviceHardware?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4)
Tff7b72val Te6edf3deviceHardware Tff7b72= Te6edf3_deviceHardwareTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3_currentFirmwareVersion Tff7b72= Te6edf3MutableStateFlowTff7b72<Tffa657String?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4)
Tff7b72val Te6edf3currentFirmwareVersion Tff7b72= Te6edf3_currentFirmwareVersionTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3_pendingLocalFirmwareFile Tff7b72= Te6edf3MutableStateFlowTff7b72<Te6edf3PendingLocalFirmwareFile?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4)
Tff7b72val Te6edf3pendingLocalFirmwareFileTb4b4b4: Te6edf3StateFlowTff7b72<Te6edf3PendingLocalFirmwareFile?Tff7b72> Tff7b72= Te6edf3_pendingLocalFirmwareFileTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72var Te6edf3updateJobTb4b4b4: Te6edf3Job? Tff7b72= Tff7b72null
Tff7b72private Tff7b72var Te6edf3prepareJobTb4b4b4: Te6edf3Job? Tff7b72= Tff7b72null
Tff7b72private Tff7b72var Te6edf3tempFirmwareFileTb4b4b4: Te6edf3FirmwareArtifact? Tff7b72= Tff7b72null
Tff7b72private Tff7b72var Te6edf3pendingLocalFirmwareArtifactTb4b4b4: Te6edf3FirmwareArtifact? Tff7b72= Tff7b72null
Tff7b72private Tff7b72var Te6edf3originalDeviceAddressTb4b4b4: Tffa657String? Tff7b72= Tff7b72null
T8b949e/** Set when [checkForUpdates] enters recovery mode (disconnected + a saved record); consumed by [startUpdate]. */
Tff7b72private Tff7b72var Te6edf3pendingRecoveryTb4b4b4: Te6edf3PendingFirmwareRecovery? Tff7b72= Tff7b72null
Tff7b72init Tb4b4b4{
T8b949e// Cleanup potential leftovers
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Te6edf3tempFirmwareFile Tff7b72= Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFileTb4b4b4)
Te6edf3checkForUpdatesTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tf0883e@OptInTb4b4b4(Te6edf3DelicateCoroutinesApiTff7b72::Te6edf3classTb4b4b4)
Tff7b72override Tff7b72fun Td2a8ffonClearedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72superTb4b4b4.Te6edf3onClearedTb4b4b4(Tb4b4b4)
Te6edf3prepareJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3prepareJob Tff7b72= Tff7b72null
T8b949e// viewModelScope is already cancelled when onCleared() runs, so launch cleanup on the
T8b949e// application-wide scope (SupervisorJob + ioDispatcher). ATOMIC start + NonCancellable
T8b949e// context keeps cleanup running even if something tries to cancel it mid-flight.
Tff7b72val Te6edf3pendingArtifact Tff7b72= Te6edf3pendingLocalFirmwareArtifact
Te6edf3pendingLocalFirmwareArtifact Tff7b72= Tff7b72null
Te6edf3applicationScopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3start Tff7b72= Te6edf3CoroutineStartTb4b4b4.Te6edf3ATOMICTb4b4b4) Tb4b4b4{
Te6edf3withContextTb4b4b4(Te6edf3NonCancellableTb4b4b4) Tb4b4b4{
Te6edf3tempFirmwareFile Tff7b72= Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFileTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3pendingArtifact Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72& Te6edf3pendingArtifact Tff7b72!Tff7b72= Te6edf3tempFirmwareFileTb4b4b4) Tb4b4b4{
Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3pendingArtifactTb4b4b4)
Tb4b4b4}
Te6edf3safeCatching Tb4b4b4{ Te6edf3fileHandlerTb4b4b4.Te6edf3cleanupAllTemporaryFilesTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3onFailure Tb4b4b4{ Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to cleanup remaining temp filesTa5d6ff" Tb4b4b4} Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffsetReleaseTypeTb4b4b4(Te6edf3typeTb4b4b4: Te6edf3FirmwareReleaseTypeTb4b4b4) Tb4b4b4{
Te6edf3_selectedReleaseTypeTb4b4b4.Te6edf3value Tff7b72= Te6edf3type
Te6edf3checkForUpdatesTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72fun Td2a8ffcancelUpdateTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3updateJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3clearPendingLocalFirmwareFileTb4b4b4(Tb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Idle
Te6edf3checkForUpdatesTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffLongMethodTa5d6ff"Tb4b4b4)
Tff7b72fun Td2a8ffcheckForUpdatesTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3updateJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3clearPendingLocalFirmwareFileTb4b4b4(Tb4b4b4)
Te6edf3updateJob Tff7b72=
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Checking
Te6edf3safeCatching Tb4b4b4{
Tff7b72val Te6edf3ourNode Tff7b72= Te6edf3nodeRepositoryTb4b4b4.Te6edf3myNodeInfoTb4b4b4.Te6edf3value
Tff7b72val Te6edf3address Tff7b72= Te6edf3radioPrefsTb4b4b4.Te6edf3devAddrTb4b4b4.Te6edf3valueTff7b72?.Te6edf3dropTb4b4b4(T79c0ff1Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3address Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3ourNode Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
T8b949e// Not connected: offer to re-flash a device stranded in bootloader mode if we saved a
T8b949e// recovery record when its (now-interrupted) update was triggered. Otherwise, no device.
Te6edf3enterRecoveryModeOrErrorTb4b4b4(Tb4b4b4)
Tff7b72returnTf0883e@launch
Tb4b4b4}
Tff7b72val Te6edf3deviceHardware Tff7b72= Te6edf3getDeviceHardwareTb4b4b4(Te6edf3ourNodeTb4b4b4) Tff7b72?: Tff7b72returnTf0883e@launch
Te6edf3_deviceHardwareTb4b4b4.Te6edf3value Tff7b72= Te6edf3deviceHardware
Te6edf3_currentFirmwareVersionTb4b4b4.Te6edf3value Tff7b72= Te6edf3ourNodeTb4b4b4.Te6edf3firmwareVersion
Tff7b72val Te6edf3releaseFlow Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3_selectedReleaseTypeTb4b4b4.Te6edf3value Tff7b72=Tff7b72= Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3LOCALTb4b4b4) Tb4b4b4{
Te6edf3flowOfTb4b4b4(Tff7b72nullTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3firmwareReleaseRepositoryTb4b4b4.Te6edf3getReleaseFlowTb4b4b4(Te6edf3_selectedReleaseTypeTb4b4b4.Te6edf3valueTb4b4b4)
Tb4b4b4}
Te6edf3releaseFlowTb4b4b4.Te6edf3collectLatest Tb4b4b4{ Te6edf3release Tff7b72-Tff7b72>
Te6edf3_selectedReleaseTb4b4b4.Te6edf3value Tff7b72= Te6edf3release
Tff7b72val Te6edf3dismissed Tff7b72= Te6edf3bootloaderWarningDataSourceTb4b4b4.Te6edf3isDismissedTb4b4b4(Te6edf3addressTb4b4b4)
Tff7b72val Te6edf3firmwareUpdateMethod Tff7b72=
Tff7b72when Tb4b4b4{
Te6edf3radioPrefsTb4b4b4.Te6edf3isSerialTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tb4b4b4{
T8b949e// Serial OTA is not yet supported for ESP32 — only nRF52/RP2040 UF2.
Tff7b72if Tb4b4b4(Te6edf3deviceHardwareTb4b4b4.Te6edf3isEsp32ArcTb4b4b4) Tb4b4b4{
Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Unknown
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Usb
Tb4b4b4}
Tb4b4b4}
Te6edf3radioPrefsTb4b4b4.Te6edf3isBleTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Ble
Te6edf3radioPrefsTb4b4b4.Te6edf3isTcpTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tb4b4b4{
T8b949e// WiFi OTA is ESP32-only; nRF52/RP2040 have no TCP update path.
Tff7b72if Tb4b4b4(Te6edf3deviceHardwareTb4b4b4.Te6edf3isEsp32ArcTb4b4b4) Tb4b4b4{
Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Wifi
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Unknown
Tb4b4b4}
Tb4b4b4}
Tff7b72else Tff7b72-Tff7b72> Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Unknown
Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4(
Te6edf3release Tff7b72= Te6edf3releaseTb4b4b4,
Te6edf3deviceHardware Tff7b72= Te6edf3deviceHardwareTb4b4b4,
Te6edf3address Tff7b72= Te6edf3addressTb4b4b4,
Te6edf3showBootloaderWarning Tff7b72=
Te6edf3deviceHardwareTb4b4b4.Te6edf3requiresBootloaderUpgradeForOta Tff7b72=Tff7b72= Tff7b72true Tff7b72&Tff7b72&
Tff7b72!Te6edf3dismissed Tff7b72&Tff7b72&
Te6edf3radioPrefsTb4b4b4.Te6edf3isBleTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3updateMethod Tff7b72= Te6edf3firmwareUpdateMethodTb4b4b4,
Te6edf3currentFirmwareVersion Tff7b72= Te6edf3ourNodeTb4b4b4.Te6edf3firmwareVersionTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4.Te6edf3onFailure Tb4b4b4{ Te6edf3e Tff7b72-Tff7b72>
Te6edf3LoggerTb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffError checking for updatesTa5d6ff" Tb4b4b4}
Tff7b72val Te6edf3unknownError Tff7b72= Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_unknown_errorTb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(
Tff7b72if Tb4b4b4(Te6edf3eTb4b4b4.Te6edf3message Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Te6edf3UiTextTb4b4b4.Te6edf3DynamicStringTb4b4b4(Te6edf3eTb4b4b4.Te6edf3messageTff7b72!!Tb4b4b4) Tff7b72else Te6edf3unknownErrorTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
T8b949e/**
* Disconnected entry point: if a firmware update was interrupted and left a device stranded in bootloader mode,
* rebuild a recovery-flavored [FirmwareUpdateState.Ready] from the saved record so the user can re-flash it without
* first reconnecting (the bootloader exposes no mesh service to connect to). No record ⇒ the usual "no device".
*/
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffenterRecoveryModeOrErrorTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3recovery Tff7b72= Te6edf3firmwareRecoveryDataSourceTb4b4b4.Te6edf3pendingTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3recovery Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3clearDeviceMetadataTb4b4b4(Tb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_no_deviceTb4b4b4)Tb4b4b4)
Tff7b72return
Tb4b4b4}
Te6edf3pendingRecovery Tff7b72= Te6edf3recovery
Tff7b72val Te6edf3hardware Tff7b72=
Te6edf3deviceHardwareRepositoryTb4b4b4.Te6edf3getDeviceHardwareByModelTb4b4b4(Te6edf3recoveryTb4b4b4.Te6edf3hwModelTb4b4b4, Te6edf3recoveryTb4b4b4.Te6edf3pioEnvTb4b4b4)Tb4b4b4.Te6edf3getOrElse Tb4b4b4{
Te6edf3clearDeviceMetadataTb4b4b4(Tb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_unknown_hardwareTb4b4b4, Te6edf3recoveryTb4b4b4.Te6edf3hwModelTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72null
Tb4b4b4} Tff7b72?: Tff7b72return
Te6edf3_deviceHardwareTb4b4b4.Te6edf3value Tff7b72= Te6edf3hardware
Te6edf3_currentFirmwareVersionTb4b4b4.Te6edf3value Tff7b72= Tff7b72null
Tff7b72val Te6edf3type Tff7b72=
Te6edf3runCatching Tb4b4b4{ Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3valueOfTb4b4b4(Te6edf3recoveryTb4b4b4.Te6edf3releaseTypeTb4b4b4) Tb4b4b4}Tb4b4b4.Te6edf3getOrDefaultTb4b4b4(Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3STABLETb4b4b4)
T8b949e// A nightly recovery record can only exist if the user had unlocked the hidden channel and deliberately
T8b949e// flashed nightly before the interruption; re-assert the (process-scoped) unlock so the recovery UI can
T8b949e// show and re-fetch that channel instead of leaving the stranded device unrecoverable.
Tff7b72if Tb4b4b4(Te6edf3type Tff7b72=Tff7b72= Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3NIGHTLYTb4b4b4) Tb4b4b4{
Te6edf3hiddenFeaturesUnlockTb4b4b4.Te6edf3unlockTb4b4b4(Tb4b4b4)
Tb4b4b4}
Te6edf3_selectedReleaseTypeTb4b4b4.Te6edf3value Tff7b72= Te6edf3type
Te6edf3firmwareReleaseRepositoryTb4b4b4.Te6edf3getReleaseFlowTb4b4b4(Te6edf3typeTb4b4b4)Tb4b4b4.Te6edf3collectLatest Tb4b4b4{ Te6edf3release Tff7b72-Tff7b72>
Te6edf3_selectedReleaseTb4b4b4.Te6edf3value Tff7b72= Te6edf3release
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4(
Te6edf3release Tff7b72= Te6edf3releaseTb4b4b4,
Te6edf3deviceHardware Tff7b72= Te6edf3hardwareTb4b4b4,
Te6edf3address Tff7b72= Te6edf3recoveryTb4b4b4.Te6edf3fullAddressTb4b4b4.Te6edf3dropTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4,
Te6edf3showBootloaderWarning Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3updateMethod Tff7b72= Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3BleTb4b4b4,
Te6edf3currentFirmwareVersion Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3isRecovery Tff7b72= Tff7b72trueTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffstartUpdateTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentState Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72as? Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Ready Tff7b72?: Tff7b72return
Tff7b72val Te6edf3release Tff7b72= Te6edf3currentStateTb4b4b4.Te6edf3release Tff7b72?: Tff7b72return
T8b949e// Explicit mapping instead of class-name reflection: FirmwareUpdateMethod is R8-obfuscated in release.
Tff7b72val Te6edf3updateMethod Tff7b72=
Tff7b72when Tb4b4b4(Te6edf3currentStateTb4b4b4.Te6edf3updateMethodTb4b4b4) Tb4b4b4{
Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Usb Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffusbTa5d6ff"
Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Ble Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffbleTa5d6ff"
Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Wifi Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffwifiTa5d6ff"
Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Unknown Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffunknownTa5d6ff"
Tb4b4b4}
Te6edf3analyticsTb4b4b4.Te6edf3trackActionTb4b4b4(
Ta5d6ff"Ta5d6fffirmware_update_startTa5d6ff"Tb4b4b4,
Te6edf3mapOfTb4b4b4(
Ta5d6ff"Ta5d6ffupdate_methodTa5d6ff" Te6edf3to Te6edf3updateMethodTb4b4b4,
Ta5d6ff"Ta5d6ffis_recoveryTa5d6ff" Te6edf3to Te6edf3currentStateTb4b4b4.Te6edf3isRecoveryTb4b4b4,
Ta5d6ff"Ta5d6ffrelease_versionTa5d6ff" Te6edf3to Te6edf3releaseTb4b4b4.Te6edf3idTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3currentStateTb4b4b4.Te6edf3isRecoveryTb4b4b4) Tb4b4b4{
Te6edf3startRecoveryUpdateTb4b4b4(Te6edf3currentStateTb4b4b4, Te6edf3releaseTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3startNormalUpdateTb4b4b4(Te6edf3currentStateTb4b4b4, Te6edf3releaseTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffstartNormalUpdateTb4b4b4(Te6edf3currentStateTb4b4b4: Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4, Te6edf3releaseTb4b4b4: Te6edf3FirmwareReleaseTb4b4b4) Tb4b4b4{
Te6edf3originalDeviceAddress Tff7b72= Te6edf3radioPrefsTb4b4b4.Te6edf3devAddrTb4b4b4.Te6edf3value
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3checkBatteryLevelTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3updateJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3updateJob Tff7b72=
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Tff7b72try Tb4b4b4{
T8b949e// Persist a recovery record before flashing so a stranded bootloader (interrupted upload,
T8b949e// app closed, missed reconnect) can be re-flashed later while disconnected.
Te6edf3maybeRecordRecoveryTb4b4b4(Te6edf3currentStateTb4b4b4)
Te6edf3tempFirmwareFile Tff7b72=
Te6edf3firmwareUpdateManagerTb4b4b4.Te6edf3startUpdateTb4b4b4(
Te6edf3release Tff7b72= Te6edf3releaseTb4b4b4,
Te6edf3hardware Tff7b72= Te6edf3currentStateTb4b4b4.Te6edf3deviceHardwareTb4b4b4,
Te6edf3address Tff7b72= Te6edf3currentStateTb4b4b4.Te6edf3addressTb4b4b4,
Te6edf3updateState Tff7b72= Tb4b4b4{ Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Tffa657it Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72when Tb4b4b4(Tff7b72val Te6edf3finalState Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3valueTb4b4b4) Tb4b4b4{
Tff7b72is Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Success Tff7b72-Tff7b72>
Te6edf3verifyUpdateResultTb4b4b4(Te6edf3originalDeviceAddressTb4b4b4, Te6edf3finalStateTb4b4b4.Te6edf3wasLowSpeedTransferTb4b4b4)
T8b949e// USB/UF2 path intentionally pauses here: the UI launches the file picker and
T8b949e// saveDfuFile() resumes the flow. Leave the state intact (tempFirmwareFile holds
T8b949e// the artifact for cleanup after the copy completes).
Tff7b72is Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3AwaitingFileSave Tff7b72-Tff7b72> Tffa657Unit
Tff7b72is Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Error Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3tempFirmwareFile Tff7b72= Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFileTb4b4b4)
Tb4b4b4}
Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
T8b949e// Defense-in-depth: handler returned without setting a terminal state
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffFirmware update returned without terminal state: Tffd700${Te6edf3_stateTb4b4b4.Te6edf3valueTffd700}Ta5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_failedTb4b4b4)Tb4b4b4)
Te6edf3tempFirmwareFile Tff7b72= Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFileTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3CancellationExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFirmware update cancelled — cause: Tffd700${Te6edf3eTb4b4b4.Te6edf3causeTffd700}Ta5d6ff message: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Idle
Te6edf3checkForUpdatesTb4b4b4(Tb4b4b4)
Tff7b72throw Te6edf3e
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFirmware update failedTa5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_failedTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
T8b949e/**
* Persist a [PendingFirmwareRecovery] for the current BLE nRF-DFU update, so an interrupted flash that strands the
* device in bootloader mode can be recovered later. Scoped to BLE + non-ESP32 + a re-fetchable release channel
* (STABLE/ALPHA/NIGHTLY); ESP32 OTA and local-file flashes are intentionally not recoverable in this flow. A
* NIGHTLY record re-asserts the hidden-features unlock on recovery (see [enterRecoveryModeOrError]).
*/
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffmaybeRecordRecoveryTb4b4b4(Te6edf3stateTb4b4b4: Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3type Tff7b72= Te6edf3_selectedReleaseTypeTb4b4b4.Te6edf3value
Tff7b72val Te6edf3recoverable Tff7b72=
Te6edf3stateTb4b4b4.Te6edf3updateMethod Tff7b72is Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Ble Tff7b72&Tff7b72&
Tff7b72!Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3isEsp32Arc Tff7b72&Tff7b72&
Te6edf3type Tff7b72!Tff7b72= Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3LOCAL
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3recoverableTb4b4b4) Tff7b72return
Tff7b72val Te6edf3fullAddress Tff7b72= Te6edf3radioPrefsTb4b4b4.Te6edf3devAddrTb4b4b4.Te6edf3value
Tff7b72val Te6edf3pioEnv Tff7b72= Te6edf3nodeRepositoryTb4b4b4.Te6edf3myNodeInfoTb4b4b4.Te6edf3valueTff7b72?.Te6edf3pioEnv
Tff7b72if Tb4b4b4(Te6edf3fullAddress Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3pioEnv Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tff7b72return
Te6edf3firmwareRecoveryDataSourceTb4b4b4.Te6edf3setTb4b4b4(
Te6edf3PendingFirmwareRecoveryTb4b4b4(
Te6edf3fullAddress Tff7b72= Te6edf3fullAddressTb4b4b4,
Te6edf3hwModel Tff7b72= Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3hwModelTb4b4b4,
Te6edf3pioEnv Tff7b72= Te6edf3pioEnvTb4b4b4,
Te6edf3releaseType Tff7b72= Te6edf3typeTb4b4b4.Te6edf3nameTb4b4b4,
Te6edf3deviceName Tff7b72= Te6edf3radioPrefsTb4b4b4.Te6edf3devNameTb4b4b4.Te6edf3value Tff7b72?: Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3displayNameTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
T8b949e/**
* Re-flash a device stranded in bootloader mode. Routes straight to BLE DFU (the device is disconnected, so the
* connection-type dispatch can't run) and reuses the same verify/cleanup tail as a normal update.
*/
Tff7b72private Tff7b72fun Td2a8ffstartRecoveryUpdateTb4b4b4(Te6edf3currentStateTb4b4b4: Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4, Te6edf3releaseTb4b4b4: Te6edf3FirmwareReleaseTb4b4b4) Tb4b4b4{
Te6edf3originalDeviceAddress Tff7b72= Te6edf3pendingRecoveryTff7b72?.Te6edf3fullAddress
Te6edf3updateJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3updateJob Tff7b72=
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3tempFirmwareFile Tff7b72=
Te6edf3firmwareUpdateManagerTb4b4b4.Te6edf3recoverDfuDeviceTb4b4b4(
Te6edf3release Tff7b72= Te6edf3releaseTb4b4b4,
Te6edf3hardware Tff7b72= Te6edf3currentStateTb4b4b4.Te6edf3deviceHardwareTb4b4b4,
Te6edf3address Tff7b72= Te6edf3currentStateTb4b4b4.Te6edf3addressTb4b4b4,
Te6edf3updateState Tff7b72= Tb4b4b4{ Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Tffa657it Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72when Tb4b4b4(Tff7b72val Te6edf3finalState Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3valueTb4b4b4) Tb4b4b4{
Tff7b72is Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Success Tff7b72-Tff7b72>
Te6edf3verifyUpdateResultTb4b4b4(Te6edf3originalDeviceAddressTb4b4b4, Te6edf3finalStateTb4b4b4.Te6edf3wasLowSpeedTransferTb4b4b4)
Tff7b72is Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Error Tff7b72-Tff7b72> Tb4b4b4{
T8b949e// BLE re-flash of a stranded device failed. A stock nRF bootloader can't reliably finish
T8b949e// an interrupted OTA update over the air, so point the user at USB serial-DFU recovery
T8b949e// rather than surfacing the low-level connection error.
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_recovery_ble_failedTb4b4b4)Tb4b4b4)
Te6edf3tempFirmwareFile Tff7b72= Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFileTb4b4b4)
Tb4b4b4}
Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffFirmware recovery returned without terminal state: Tffd700${Te6edf3_stateTb4b4b4.Te6edf3valueTffd700}Ta5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_recovery_ble_failedTb4b4b4)Tb4b4b4)
Te6edf3tempFirmwareFile Tff7b72= Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFileTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3CancellationExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFirmware recovery cancelledTa5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Idle
Te6edf3checkForUpdatesTb4b4b4(Tb4b4b4)
Tff7b72throw Te6edf3e
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFirmware recovery failedTa5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_recovery_ble_failedTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffsaveDfuFileTb4b4b4(Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentState Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72as? Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3AwaitingFileSave Tff7b72?: Tff7b72return
Tff7b72val Te6edf3firmwareArtifact Tff7b72= Te6edf3currentStateTb4b4b4.Te6edf3uf2Artifact
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Tff7b72try Tb4b4b4{
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ProcessingTb4b4b4(Te6edf3ProgressStateTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_copyingTb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3fileHandlerTb4b4b4.Te6edf3copyToUriTb4b4b4(Te6edf3firmwareArtifactTb4b4b4, Te6edf3uriTb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ProcessingTb4b4b4(Te6edf3ProgressStateTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_flashingTb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3withTimeoutOrNullTb4b4b4(Te6edf3DEVICE_DETACH_TIMEOUTTb4b4b4) Tb4b4b4{ Te6edf3usbManagerTb4b4b4.Te6edf3deviceDetachFlowTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72?: Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffTimed out waiting for device to detach, assuming successTa5d6ff" Tb4b4b4}
Te6edf3verifyUpdateResultTb4b4b4(Te6edf3originalDeviceAddressTb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3CancellationExceptionTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3e
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffError saving DFU fileTa5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_failedTb4b4b4)Tb4b4b4)
Tb4b4b4} Tff7b72finally Tb4b4b4{
Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFileTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffprepareLocalFirmwareFileTb4b4b4(Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentState Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72as? Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Ready Tff7b72?: Tff7b72return
Te6edf3clearPendingLocalFirmwareFileTb4b4b4(Tb4b4b4)
Te6edf3prepareJob Tff7b72=
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72val Te6edf3fileName Tff7b72=
Te6edf3safeCatching Tb4b4b4{ Te6edf3fileHandlerTb4b4b4.Te6edf3getDisplayNameTb4b4b4(Te6edf3uriTb4b4b4)Tff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isNotBlankTb4b4b4(Tb4b4b4) Tb4b4b4} Tb4b4b4}
Tb4b4b4.Te6edf3getOrElse Tb4b4b4{ Te6edf3e Tff7b72-Tff7b72>
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to resolve local firmware filenameTa5d6ff" Tb4b4b4}
Tff7b72null
Tb4b4b4}
T8b949e// State may have changed during the suspend call (e.g. cancelUpdate, checkForUpdates).
T8b949e// Do not write errors or reopen the confirmation dialog for a stale selection.
Tff7b72when Tb4b4b4{
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72!Tff7b72= Te6edf3currentState Tff7b72-Tff7b72> Tffa657Unit
Te6edf3fileName Tff7b72=Tff7b72= Tff7b72null Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_filename_unavailableTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72val Te6edf3resolution Tff7b72= Te6edf3resolveLocalFirmwareFileTb4b4b4(Te6edf3uriTb4b4b4, Te6edf3fileNameTb4b4b4, Te6edf3currentStateTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72!Tff7b72= Te6edf3currentStateTb4b4b4) Tb4b4b4{
Te6edf3cleanupResolvedLocalFirmwareFileTb4b4b4(Te6edf3resolutionTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3applyLocalFirmwareResolutionTb4b4b4(Te6edf3resolutionTb4b4b4, Te6edf3currentStateTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3CancellationExceptionTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3e
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffError preparing local firmware fileTa5d6ff" Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=Tff7b72= Te6edf3currentStateTb4b4b4) Tb4b4b4{
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_failedTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffconfirmLocalFirmwareFileTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3pendingSelection Tff7b72= Te6edf3_pendingLocalFirmwareFileTb4b4b4.Te6edf3value Tff7b72?: Tff7b72return
Tff7b72val Te6edf3pendingArtifact Tff7b72= Te6edf3pendingLocalFirmwareArtifact
Te6edf3_pendingLocalFirmwareFileTb4b4b4.Te6edf3value Tff7b72= Tff7b72null
Te6edf3pendingLocalFirmwareArtifact Tff7b72= Tff7b72null
Tff7b72val Te6edf3currentState Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72as? Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Ready
Tff7b72if Tb4b4b4(Te6edf3currentState Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3validation Tff7b72= Te6edf3validatePendingLocalFirmwareFileTb4b4b4(Te6edf3pendingSelectionTb4b4b4, Te6edf3currentStateTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3validation Tff7b72is Te6edf3LocalFirmwareFileValidationTb4b4b4.Te6edf3InvalidTb4b4b4) Tb4b4b4{
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(
Te6edf3localFirmwareValidationErrorTb4b4b4(Te6edf3validationTb4b4b4.Te6edf3reasonTb4b4b4, Te6edf3pendingSelectionTb4b4b4.Te6edf3fileNameTb4b4b4, Te6edf3currentStateTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3cleanupPendingLocalFirmwareArtifactTb4b4b4(Te6edf3pendingArtifactTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3startUpdateFromFileTb4b4b4(Te6edf3pendingSelectionTb4b4b4.Te6edf3uriTb4b4b4, Te6edf3pendingArtifactTb4b4b4)
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3cleanupPendingLocalFirmwareArtifactTb4b4b4(Te6edf3pendingArtifactTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72fun Td2a8ffdismissLocalFirmwareFileTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3clearPendingLocalFirmwareFileTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffresolveLocalFirmwareFileTb4b4b4(
Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4,
Te6edf3fileNameTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3stateTb4b4b4: Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3LocalFirmwareResolution Tb4b4b4{
Tff7b72val Te6edf3validation Tff7b72= Te6edf3validateLocalFirmwareFileNameTb4b4b4(Te6edf3fileNameTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3updateMethodTb4b4b4)
Tff7b72return Tff7b72when Tb4b4b4(Te6edf3validationTb4b4b4) Tb4b4b4{
Te6edf3LocalFirmwareFileValidationTb4b4b4.Te6edf3Valid Tff7b72-Tff7b72> Te6edf3LocalFirmwareResolutionTb4b4b4.Te6edf3ResolvedTb4b4b4(Te6edf3uri Tff7b72= Te6edf3uriTb4b4b4, Te6edf3fileName Tff7b72= Te6edf3fileNameTb4b4b4)
Tff7b72is Te6edf3LocalFirmwareFileValidationTb4b4b4.Te6edf3Invalid Tff7b72-Tff7b72>
Tff7b72if Tb4b4b4(Te6edf3shouldTryLocalFirmwareBundleTb4b4b4(Te6edf3fileNameTb4b4b4, Te6edf3validationTb4b4b4.Te6edf3reasonTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3resolveLocalFirmwareBundleTb4b4b4(Te6edf3uriTb4b4b4, Te6edf3fileNameTb4b4b4, Te6edf3stateTb4b4b4, Te6edf3validationTb4b4b4.Te6edf3reasonTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3LocalFirmwareResolutionTb4b4b4.Te6edf3InvalidTb4b4b4(Te6edf3reason Tff7b72= Te6edf3validationTb4b4b4.Te6edf3reasonTb4b4b4, Te6edf3fileName Tff7b72= Te6edf3fileNameTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffresolveLocalFirmwareBundleTb4b4b4(
Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4,
Te6edf3fileNameTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3stateTb4b4b4: Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4,
Te6edf3fallbackReasonTb4b4b4: Te6edf3LocalFirmwareFileValidationReasonTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3LocalFirmwareResolution Tb4b4b4{
Tff7b72val Te6edf3payloadExtension Tff7b72= Te6edf3localFirmwarePayloadExtensionTb4b4b4(Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3updateMethodTb4b4b4)
Tff7b72return Tff7b72if Tb4b4b4(Te6edf3payloadExtension Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3LocalFirmwareResolutionTb4b4b4.Te6edf3InvalidTb4b4b4(Te6edf3reason Tff7b72= Te6edf3fallbackReasonTb4b4b4, Te6edf3fileName Tff7b72= Te6edf3fileNameTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72val Te6edf3extractingState Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ProcessingTb4b4b4(Te6edf3ProgressStateTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_extractingTb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3extractingState
Tff7b72try Tb4b4b4{
Tff7b72val Te6edf3extractedArtifact Tff7b72= Te6edf3extractLocalFirmwareArchiveTb4b4b4(Te6edf3uriTb4b4b4, Te6edf3fileNameTb4b4b4, Te6edf3stateTb4b4b4, Te6edf3payloadExtensionTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3extractedArtifact Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3LocalFirmwareResolutionTb4b4b4.Te6edf3InvalidTb4b4b4(
Te6edf3reason Tff7b72= Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3MissingArchiveFirmwareTb4b4b4,
Te6edf3fileName Tff7b72= Te6edf3fileNameTb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3validateExtractedLocalFirmwareTb4b4b4(Te6edf3extractedArtifactTb4b4b4, Te6edf3fileNameTb4b4b4, Te6edf3stateTb4b4b4)
Tb4b4b4}
Tb4b4b4} Tff7b72finally Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=Tff7b72= Te6edf3extractingStateTb4b4b4) Tb4b4b4{
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3state
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffextractLocalFirmwareArchiveTb4b4b4(
Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4,
Te6edf3fileNameTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3stateTb4b4b4: Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4,
Te6edf3payloadExtensionTb4b4b4: Tffa657StringTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3FirmwareArtifact? Tb4b4b4{
Tff7b72val Te6edf3preferredFilenames Tff7b72=
Te6edf3preferredLocalFirmwareArchiveFilenamesTb4b4b4(Te6edf3fileNameTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3updateMethodTb4b4b4)
Tff7b72for Tb4b4b4(Te6edf3preferredFilename Tff7b72in Te6edf3preferredFilenamesTb4b4b4) Tb4b4b4{
Te6edf3safeCatching Tb4b4b4{ Te6edf3fileHandlerTb4b4b4.Te6edf3extractFirmwareTb4b4b4(Te6edf3uriTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4, Te6edf3payloadExtensionTb4b4b4, Te6edf3preferredFilenameTb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3onFailure Tb4b4b4{ Te6edf3e Tff7b72-Tff7b72> Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to extract preferred local firmware Tffd700$Te6edf3preferredFilenameTa5d6ff" Tb4b4b4} Tb4b4b4}
Tb4b4b4.Te6edf3getOrNullTb4b4b4(Tb4b4b4)
Tff7b72?.Te6edf3let Tb4b4b4{
Tff7b72return Tffa657it
Tb4b4b4}
Tb4b4b4}
Tff7b72return Te6edf3safeCatching Tb4b4b4{ Te6edf3fileHandlerTb4b4b4.Te6edf3extractFirmwareTb4b4b4(Te6edf3uriTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4, Te6edf3payloadExtensionTb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3getOrElse Tb4b4b4{ Te6edf3e Tff7b72-Tff7b72>
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to extract local firmware archiveTa5d6ff" Tb4b4b4}
Tff7b72null
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffvalidateExtractedLocalFirmwareTb4b4b4(
Te6edf3extractedArtifactTb4b4b4: Te6edf3FirmwareArtifactTb4b4b4,
Te6edf3fallbackFileNameTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3stateTb4b4b4: Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3LocalFirmwareResolution Tb4b4b4{
Tff7b72val Te6edf3extractedFileName Tff7b72= Te6edf3extractedArtifactTb4b4b4.Te6edf3fileName
Tff7b72val Te6edf3extractedValidation Tff7b72=
Te6edf3extractedFileNameTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3validateLocalFirmwareFileNameTb4b4b4(Tffa657itTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3updateMethodTb4b4b4) Tb4b4b4}
Tff7b72?: Te6edf3LocalFirmwareFileValidationTb4b4b4.Te6edf3InvalidTb4b4b4(Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3MissingArchiveFirmwareTb4b4b4)
Tff7b72return Tff7b72if Tb4b4b4(Te6edf3extractedValidation Tff7b72=Tff7b72= Te6edf3LocalFirmwareFileValidationTb4b4b4.Te6edf3Valid Tff7b72&Tff7b72& Te6edf3extractedFileName Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3LocalFirmwareResolutionTb4b4b4.Te6edf3ResolvedTb4b4b4(
Te6edf3uri Tff7b72= Te6edf3extractedArtifactTb4b4b4.Te6edf3uriTb4b4b4,
Te6edf3fileName Tff7b72= Te6edf3extractedFileNameTb4b4b4,
Te6edf3temporaryArtifact Tff7b72= Te6edf3extractedArtifactTb4b4b4.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isTemporary Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3cleanupPendingLocalFirmwareArtifactTb4b4b4(Te6edf3extractedArtifactTb4b4b4)
Te6edf3LocalFirmwareResolutionTb4b4b4.Te6edf3InvalidTb4b4b4(
Te6edf3reason Tff7b72= Tb4b4b4(Te6edf3extractedValidation Tff7b72as Te6edf3LocalFirmwareFileValidationTb4b4b4.Te6edf3InvalidTb4b4b4)Tb4b4b4.Te6edf3reasonTb4b4b4,
Te6edf3fileName Tff7b72= Te6edf3extractedFileName Tff7b72?: Te6edf3fallbackFileNameTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffapplyLocalFirmwareResolutionTb4b4b4(Te6edf3resolutionTb4b4b4: Te6edf3LocalFirmwareResolutionTb4b4b4, Te6edf3stateTb4b4b4: Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4) Tb4b4b4{
Tff7b72when Tb4b4b4(Te6edf3resolutionTb4b4b4) Tb4b4b4{
Tff7b72is Te6edf3LocalFirmwareResolutionTb4b4b4.Te6edf3Invalid Tff7b72-Tff7b72>
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(
Te6edf3localFirmwareValidationErrorTb4b4b4(Te6edf3resolutionTb4b4b4.Te6edf3reasonTb4b4b4, Te6edf3resolutionTb4b4b4.Te6edf3fileNameTb4b4b4, Te6edf3stateTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72is Te6edf3LocalFirmwareResolutionTb4b4b4.Te6edf3Resolved Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3pendingLocalFirmwareArtifact Tff7b72= Te6edf3resolutionTb4b4b4.Te6edf3temporaryArtifact
Te6edf3_pendingLocalFirmwareFileTb4b4b4.Te6edf3value Tff7b72=
Te6edf3PendingLocalFirmwareFileTb4b4b4(
Te6edf3uri Tff7b72= Te6edf3resolutionTb4b4b4.Te6edf3uriTb4b4b4,
Te6edf3fileName Tff7b72= Te6edf3resolutionTb4b4b4.Te6edf3fileNameTb4b4b4,
Te6edf3deviceName Tff7b72= Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3displayNameTb4b4b4,
Te6edf3platformioTarget Tff7b72= Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3effectiveTargetTb4b4b4,
Te6edf3updateMethod Tff7b72= Te6edf3stateTb4b4b4.Te6edf3updateMethodTb4b4b4,
Te6edf3address Tff7b72= Te6edf3stateTb4b4b4.Te6edf3addressTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffcleanupResolvedLocalFirmwareFileTb4b4b4(Te6edf3resolutionTb4b4b4: Te6edf3LocalFirmwareResolutionTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3resolution Tff7b72is Te6edf3LocalFirmwareResolutionTb4b4b4.Te6edf3ResolvedTb4b4b4) Tb4b4b4{
Te6edf3cleanupPendingLocalFirmwareArtifactTb4b4b4(Te6edf3resolutionTb4b4b4.Te6edf3temporaryArtifactTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffclearPendingLocalFirmwareFileTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3prepareJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3prepareJob Tff7b72= Tff7b72null
Tff7b72val Te6edf3artifact Tff7b72= Te6edf3pendingLocalFirmwareArtifact
Te6edf3_pendingLocalFirmwareFileTb4b4b4.Te6edf3value Tff7b72= Tff7b72null
Te6edf3pendingLocalFirmwareArtifact Tff7b72= Tff7b72null
Te6edf3cleanupPendingLocalFirmwareArtifactTb4b4b4(Te6edf3artifactTb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffcleanupPendingLocalFirmwareArtifactTb4b4b4(Te6edf3artifactTb4b4b4: Te6edf3FirmwareArtifact?Tb4b4b4) Tb4b4b4{
Te6edf3artifact
Tff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isTemporary Tb4b4b4}
Tff7b72?.Te6edf3let Tb4b4b4{
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Te6edf3safeCatching Tb4b4b4{ Te6edf3fileHandlerTb4b4b4.Te6edf3deleteFileTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3onFailure Tb4b4b4{ Te6edf3e Tff7b72-Tff7b72> Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to cleanup pending local firmware fileTa5d6ff" Tb4b4b4} Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffstartUpdateFromFileTb4b4b4(Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4, Te6edf3pendingArtifactTb4b4b4: Te6edf3FirmwareArtifact? Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentState Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72as? Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Ready Tff7b72?: Tff7b72return
Tff7b72if Tb4b4b4(Te6edf3currentStateTb4b4b4.Te6edf3updateMethod Tff7b72is Te6edf3FirmwareUpdateMethodTb4b4b4.Te6edf3Ble Tff7b72&Tff7b72& Tff7b72!Te6edf3isValidBluetoothAddressTb4b4b4(Te6edf3currentStateTb4b4b4.Te6edf3addressTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_no_deviceTb4b4b4)Tb4b4b4)
Te6edf3cleanupPendingLocalFirmwareArtifactTb4b4b4(Te6edf3pendingArtifactTb4b4b4)
Tff7b72return
Tb4b4b4}
Te6edf3originalDeviceAddress Tff7b72= Te6edf3radioPrefsTb4b4b4.Te6edf3devAddrTb4b4b4.Te6edf3value
Te6edf3updateJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3updateJob Tff7b72=
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72val Te6edf3updateArtifact Tff7b72=
Te6edf3firmwareUpdateManagerTb4b4b4.Te6edf3startUpdateTb4b4b4(
Te6edf3release Tff7b72= Te6edf3FirmwareReleaseTb4b4b4(Te6edf3id Tff7b72= Te6edf3LOCAL_RELEASE_IDTb4b4b4, Te6edf3zipUrl Tff7b72= Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3releaseNotes Tff7b72= Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3hardware Tff7b72= Te6edf3currentStateTb4b4b4.Te6edf3deviceHardwareTb4b4b4,
Te6edf3address Tff7b72= Te6edf3currentStateTb4b4b4.Te6edf3addressTb4b4b4,
Te6edf3updateState Tff7b72= Tb4b4b4{ Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Tffa657it Tb4b4b4}Tb4b4b4,
Te6edf3firmwareUri Tff7b72= Te6edf3uriTb4b4b4,
Tb4b4b4)
Te6edf3tempFirmwareFile Tff7b72= Te6edf3updateArtifactTff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isTemporary Tb4b4b4} Tff7b72?: Te6edf3pendingArtifact
T8b949e// If the handler created its own temp copy (e.g. ESP32 importFromUri),
T8b949e// clean up the extracted bundle artifact to prevent a leak.
Tff7b72if Tb4b4b4(Te6edf3pendingArtifact Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72& Te6edf3pendingArtifact Tff7b72!Tff7b72= Te6edf3tempFirmwareFileTb4b4b4) Tb4b4b4{
Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3pendingArtifactTb4b4b4)
Tb4b4b4}
Tff7b72when Tb4b4b4(Tff7b72val Te6edf3finalState Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3valueTb4b4b4) Tb4b4b4{
Tff7b72is Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Success Tff7b72-Tff7b72>
Te6edf3verifyUpdateResultTb4b4b4(Te6edf3originalDeviceAddressTb4b4b4, Te6edf3finalStateTb4b4b4.Te6edf3wasLowSpeedTransferTb4b4b4)
T8b949e// USB/UF2 path pauses here for the user to pick a save location; saveDfuFile() resumes it.
Tff7b72is Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3AwaitingFileSave Tff7b72-Tff7b72> Tffa657Unit
Tff7b72is Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Error Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3tempFirmwareFile Tff7b72= Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFileTb4b4b4)
Tb4b4b4}
Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffFirmware update returned without terminal state: Tffd700${Te6edf3_stateTb4b4b4.Te6edf3valueTffd700}Ta5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_failedTb4b4b4)Tb4b4b4)
Te6edf3tempFirmwareFile Tff7b72= Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFileTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3CancellationExceptionTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3e
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffError starting update from fileTa5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_failedTb4b4b4)Tb4b4b4)
Te6edf3tempFirmwareFile Tff7b72= Te6edf3cleanupTemporaryFilesTb4b4b4(Te6edf3fileHandlerTb4b4b4, Te6edf3tempFirmwareFile Tff7b72?: Te6edf3pendingArtifactTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8fflocalFirmwareValidationErrorTb4b4b4(
Te6edf3reasonTb4b4b4: Te6edf3LocalFirmwareFileValidationReasonTb4b4b4,
Te6edf3fileNameTb4b4b4: Tffa657StringTb4b4b4,
Te6edf3stateTb4b4b4: Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ReadyTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3UiText Tff7b72= Tff7b72when Tb4b4b4(Te6edf3reasonTb4b4b4) Tb4b4b4{
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3MissingArchiveFirmware Tff7b72-Tff7b72>
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(
Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_archive_missing_targetTb4b4b4,
Te6edf3fileNameTb4b4b4,
Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3displayNameTb4b4b4,
Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3effectiveTargetTb4b4b4,
Tb4b4b4)
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3MissingTarget Tff7b72-Tff7b72>
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_missing_targetTb4b4b4)
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3UnsupportedUpdateMethod Tff7b72-Tff7b72>
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_unsupported_update_methodTb4b4b4)
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3RequiresOtaZip Tff7b72-Tff7b72>
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_requires_ota_zipTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3displayNameTb4b4b4)
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3RequiresBin Tff7b72-Tff7b72>
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_requires_binTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3displayNameTb4b4b4)
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3RequiresUf2 Tff7b72-Tff7b72>
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_requires_uf2Tb4b4b4, Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3displayNameTb4b4b4)
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3ConfirmationContextChanged Tff7b72-Tff7b72>
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_context_changedTb4b4b4)
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3TargetMismatch Tff7b72-Tff7b72>
Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(
Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_invalid_local_file_detailTb4b4b4,
Te6edf3fileNameTb4b4b4,
Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3displayNameTb4b4b4,
Te6edf3stateTb4b4b4.Te6edf3deviceHardwareTb4b4b4.Te6edf3effectiveTargetTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tff7b72fun Td2a8ffdismissBootloaderWarningForCurrentDeviceTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentState Tff7b72= Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72as? Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Ready Tff7b72?: Tff7b72return
Te6edf3viewModelScopeTb4b4b4.Te6edf3launch Tb4b4b4{
Te6edf3bootloaderWarningDataSourceTb4b4b4.Te6edf3dismissTb4b4b4(Te6edf3currentStateTb4b4b4.Te6edf3addressTb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3currentStateTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3showBootloaderWarning Tff7b72= Tff7b72falseTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffverifyUpdateResultTb4b4b4(Te6edf3addressTb4b4b4: Tffa657String?Tb4b4b4, Te6edf3wasLowSpeedTransferTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4) Tb4b4b4{
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3Verifying
T8b949e// Trigger a fresh connection attempt by MeshService using the original prefixed address.
T8b949e//
T8b949e// For USB/serial, do NOT force this: a USB node re-enumerates several times through the bootloader over
T8b949e// ~20s, so a one-shot setDeviceAddress fires into an enumeration gap, fails ("Serial device not found"),
T8b949e// and lands the transport in Disconnected — which preempts the dedicated USB auto-recovery in
T8b949e// SharedRadioInterfaceService (observeUsbRecoveryTriggers), since that only arms from DeviceSleep. Leaving
T8b949e// the transport in DeviceSleep lets that recovery reconnect the moment the device re-attaches on its new
T8b949e// (stable-keyed) address. BLE/TCP have no such hot-plug recovery, so they still need the explicit re-address.
Te6edf3addressTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3fullAddr Tff7b72-Tff7b72>
Tff7b72if Tb4b4b4(Te6edf3radioPrefsTb4b4b4.Te6edf3isSerialTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffPost-update: leaving USB reconnect to USB auto-recovery for Tffd700${Te6edf3fullAddrTb4b4b4.Te6edf3anonymizeTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffPost-update: Requesting MeshService to reconnect to Tffd700${Te6edf3fullAddrTb4b4b4.Te6edf3anonymizeTffd700}Ta5d6ff" Tb4b4b4}
T8b949e// GATT cache invalidation is only needed for BLE reconnects — the device
T8b949e// reboots into a different GATT profile on the same MAC address. TCP/USB
T8b949e// don't have this problem, and leaving a stale BLE-only request around
T8b949e// could trigger an unnecessary refresh on a later BLE connection.
Tff7b72if Tb4b4b4(Te6edf3isBluetoothInterfaceAddressTb4b4b4(Te6edf3fullAddrTb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffPost-update: Requesting GATT cache invalidation before BLE reconnectTa5d6ff" Tb4b4b4}
Te6edf3radioControllerTb4b4b4.Te6edf3requestGattCacheInvalidationOnNextConnectTb4b4b4(Tb4b4b4)
Tb4b4b4}
Te6edf3radioControllerTb4b4b4.Te6edf3setDeviceAddressTb4b4b4(Te6edf3fullAddrTb4b4b4)
Tb4b4b4}
Tb4b4b4}
T8b949e// Wait for device to reconnect and settle
Tff7b72val Te6edf3result Tff7b72=
Te6edf3withTimeoutOrNullTb4b4b4(Te6edf3VERIFY_TIMEOUTTb4b4b4) Tb4b4b4{
T8b949e// Wait for both Connected state and node info to be present
Te6edf3connectionStateTb4b4b4.Te6edf3first Tb4b4b4{ Tffa657it Tff7b72is Te6edf3ConnectionStateTb4b4b4.Te6edf3Connected Tb4b4b4}
Te6edf3nodeRepositoryTb4b4b4.Te6edf3ourNodeInfoTb4b4b4.Te6edf3filterNotNullTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3delayTb4b4b4(Te6edf3VERIFY_DELAYTb4b4b4) T8b949e// Extra buffer for initial config sync
Tff7b72true
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3result Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffPost-update verification timed out for Tffd700${Te6edf3addressTb4b4b4.Te6edf3anonymizeTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff" Tb4b4b4}
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3VerificationFailed
Tb4b4b4} Tff7b72else Tb4b4b4{
T8b949e// Device is back and healthy — retire any recovery record (covers both normal and recovery updates).
Te6edf3pendingRecovery Tff7b72= Tff7b72null
Te6edf3firmwareRecoveryDataSourceTb4b4b4.Te6edf3clearTb4b4b4(Tb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3SuccessTb4b4b4(Te6edf3wasLowSpeedTransferTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffcheckBatteryLevelTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3nodeRepositoryTb4b4b4.Te6edf3ourNodeInfoTb4b4b4.Te6edf3value Tff7b72?: Tff7b72return Tff7b72true
Tff7b72val Te6edf3level Tff7b72= Te6edf3nodeTb4b4b4.Te6edf3batteryLevel Tff7b72?: T79c0ff1
Tff7b72val Te6edf3isBatteryLow Tff7b72= Te6edf3level Tff7b72in T79c0ff1.Tb4b4b4.Te6edf3MIN_BATTERY_LEVEL
Tff7b72if Tb4b4b4(Te6edf3isBatteryLowTb4b4b4) Tb4b4b4{
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_battery_lowTb4b4b4, Te6edf3levelTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tff7b72return Tff7b72!Te6edf3isBatteryLow
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffgetDeviceHardwareTb4b4b4(Te6edf3ourNodeTb4b4b4: Te6edf3MyNodeInfoTb4b4b4)Tb4b4b4: Te6edf3DeviceHardware? Tb4b4b4{
Tff7b72val Te6edf3nodeInfo Tff7b72= Te6edf3nodeRepositoryTb4b4b4.Te6edf3ourNodeInfoTb4b4b4.Te6edf3value
Tff7b72val Te6edf3hwModelInt Tff7b72= Te6edf3nodeInfoTff7b72?.Te6edf3userTff7b72?.Te6edf3hw_modelTff7b72?.Te6edf3value
Tff7b72val Te6edf3target Tff7b72= Te6edf3ourNodeTb4b4b4.Te6edf3pioEnv
Tff7b72return Tff7b72if Tb4b4b4(Te6edf3hwModelInt Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3deviceHardwareRepositoryTb4b4b4.Te6edf3getDeviceHardwareByModelTb4b4b4(Te6edf3hwModelIntTb4b4b4, Te6edf3targetTb4b4b4)Tb4b4b4.Te6edf3getOrElse Tb4b4b4{
Te6edf3clearDeviceMetadataTb4b4b4(Tb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72=
Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_unknown_hardwareTb4b4b4, Te6edf3hwModelIntTb4b4b4)Tb4b4b4)
Tff7b72null
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3clearDeviceMetadataTb4b4b4(Tb4b4b4)
Te6edf3_stateTb4b4b4.Te6edf3value Tff7b72= Te6edf3FirmwareUpdateStateTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3UiTextTb4b4b4.Te6edf3ResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_node_info_missingTb4b4b4)Tb4b4b4)
Tff7b72null
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffclearDeviceMetadataTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3_selectedReleaseTb4b4b4.Te6edf3value Tff7b72= Tff7b72null
Te6edf3_deviceHardwareTb4b4b4.Te6edf3value Tff7b72= Tff7b72null
Te6edf3_currentFirmwareVersionTb4b4b4.Te6edf3value Tff7b72= Tff7b72null
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72sealed Tff7b72interface T56d364LocalFirmwareResolution Tb4b4b4{
Tff7b72data Tff7b72class T56d364ResolvedTb4b4b4(Tff7b72val Te6edf3uriTb4b4b4: Te6edf3CommonUriTb4b4b4, Tff7b72val Te6edf3fileNameTb4b4b4: Tffa657StringTb4b4b4, Tff7b72val Te6edf3temporaryArtifactTb4b4b4: Te6edf3FirmwareArtifact? Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4:
Te6edf3LocalFirmwareResolution
Tff7b72data Tff7b72class T56d364InvalidTb4b4b4(Tff7b72val Te6edf3reasonTb4b4b4: Te6edf3LocalFirmwareFileValidationReasonTb4b4b4, Tff7b72val Te6edf3fileNameTb4b4b4: Tffa657StringTb4b4b4) Tb4b4b4: Te6edf3LocalFirmwareResolution
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffshouldTryLocalFirmwareBundleTb4b4b4(Te6edf3fileNameTb4b4b4: Tffa657StringTb4b4b4, Te6edf3reasonTb4b4b4: Te6edf3LocalFirmwareFileValidationReasonTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3normalizedFileName Tff7b72= Te6edf3fileNameTb4b4b4.Te6edf3substringAfterLastTb4b4b4(Ta5d6ff'/'Tb4b4b4)Tb4b4b4.Te6edf3substringAfterLastTb4b4b4(Ta5d6ff'\\'Tb4b4b4)Tb4b4b4.Te6edf3lowercaseTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3normalizedFileNameTb4b4b4.Te6edf3endsWithTb4b4b4(Ta5d6ff"Ta5d6ff.zipTa5d6ff"Tb4b4b4) Tff7b72&Tff7b72&
Tff7b72when Tb4b4b4(Te6edf3reasonTb4b4b4) Tb4b4b4{
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3RequiresOtaZipTb4b4b4,
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3RequiresBinTb4b4b4,
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3RequiresUf2Tb4b4b4,
Tff7b72-Tff7b72> Tff7b72true
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3MissingArchiveFirmwareTb4b4b4,
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3MissingTargetTb4b4b4,
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3TargetMismatchTb4b4b4,
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3ConfirmationContextChangedTb4b4b4,
Te6edf3LocalFirmwareFileValidationReasonTb4b4b4.Te6edf3UnsupportedUpdateMethodTb4b4b4,
Tff7b72-Tff7b72> Tff7b72false
Tb4b4b4}
Tb4b4b4}
Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffcleanupTemporaryFilesTb4b4b4(
Te6edf3fileHandlerTb4b4b4: Te6edf3FirmwareFileHandlerTb4b4b4,
Te6edf3tempFirmwareFileTb4b4b4: Te6edf3FirmwareArtifact?Tb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3FirmwareArtifact? Tb4b4b4{
Te6edf3safeCatching Tb4b4b4{ Te6edf3tempFirmwareFileTff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3isTemporary Tb4b4b4}Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3fileHandlerTb4b4b4.Te6edf3deleteFileTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4} Tb4b4b4}
Tb4b4b4.Te6edf3onFailure Tb4b4b4{ Te6edf3e Tff7b72-Tff7b72> Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to cleanup temp filesTa5d6ff" Tb4b4b4} Tb4b4b4}
Tff7b72return Tff7b72null
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffisValidBluetoothAddressTb4b4b4(Te6edf3addressTb4b4b4: Tffa657String?Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3address Tff7b72!Tff7b72= Tff7b72null Tff7b72&Tff7b72& Te6edf3BLUETOOTH_ADDRESS_REGEXTb4b4b4.Te6edf3matchesTb4b4b4(Te6edf3addressTb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffisBluetoothInterfaceAddressTb4b4b4(Te6edf3addressTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72=
Te6edf3addressTb4b4b4.Te6edf3startsWithTb4b4b4(Te6edf3InterfaceIdTb4b4b4.Te6edf3BLUETOOTHTb4b4b4.Te6edf3idTb4b4b4) Tff7b72|Tff7b72| Te6edf3addressTb4b4b4.Te6edf3startsWithTb4b4b4(Ta5d6ff"Ta5d6ff!Ta5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Te6edf3FirmwareReleaseRepositoryTb4b4b4.Td2a8ffgetReleaseFlowTb4b4b4(Te6edf3typeTb4b4b4: Te6edf3FirmwareReleaseTypeTb4b4b4)Tb4b4b4: Te6edf3FlowTff7b72<Te6edf3FirmwareRelease?Tff7b72> Tff7b72= Tff7b72when Tb4b4b4(Te6edf3typeTb4b4b4) Tb4b4b4{
Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3STABLE Tff7b72-Tff7b72> Te6edf3stableRelease
Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3ALPHA Tff7b72-Tff7b72> Te6edf3alphaRelease
Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3NIGHTLY Tff7b72-Tff7b72> Te6edf3nightlyRelease
Te6edf3FirmwareReleaseTypeTb4b4b4.Te6edf3LOCAL Tff7b72-Tff7b72> Te6edf3flowOfTb4b4b4(Tff7b72nullTb4b4b4)
Tb4b4b4}
T8b949e/** The transport mechanism used to deliver firmware to the device, determined by the active radio connection. */
Tff7b72sealed Tff7b72class T56d364FirmwareUpdateMethodTb4b4b4(Tff7b72val Te6edf3descriptionTb4b4b4: Te6edf3StringResourceTb4b4b4) Tb4b4b4{
Tff7b72data Tff7b72object T56d364Usb Tb4b4b4: Te6edf3FirmwareUpdateMethodTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_method_usbTb4b4b4)
Tff7b72data Tff7b72object T56d364Ble Tb4b4b4: Te6edf3FirmwareUpdateMethodTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_method_bleTb4b4b4)
Tff7b72data Tff7b72object T56d364Wifi Tb4b4b4: Te6edf3FirmwareUpdateMethodTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3firmware_update_method_wifiTb4b4b4)
Tff7b72data Tff7b72object T56d364Unknown Tb4b4b4: Te6edf3FirmwareUpdateMethodTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3unknownTb4b4b4)
Tb4b4b4}
Served by rngit 1.4.2 - Generated in 0.21s